﻿using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using élénkPróbája.extentions;
using élénkPróbája.Test.dto;
using élénkPróbája.Test.extention;
using élénkPróbája.validators;

namespace élénkPróbája.Test
{
    [TestClass]
    public class ExclusiveBetweenValidatorTester
    {
        DateTime fromDate;
        DateTime toDate;

        public ExclusiveBetweenValidatorTester()
        {
            CultureScope.SetDefaultCulture();
            fromDate = new DateTime(2015, 1, 1);
            toDate = new DateTime(2015, 12, 31);
        }
        [TestMethod]
        public void When_the_value_is_between_the_range_specified_then_the_validator_should_pass()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 10) };
            var result = validator.Validate(new Company() { Id = 5 });
            result.IsValid.ShouldBeTrue();
        }
        [TestMethod]
        public void When_the_value_is_smaller_than_the_range_then_the_validator_should_fail()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 10) };
            var result = validator.Validate(new Company() { Id = 0 });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_text_is_larger_than_the_range_then_the_validator_should_fail()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 10) };
            var result = validator.Validate(new Company { Id = 11 });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_value_is_exactly_the_size_of_the_upper_bound_then_the_validator_should_fail()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 10) };
            var result = validator.Validate(new Company { Id = 10 });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_value_is_exactly_the_size_of_the_lower_bound_then_the_validator_should_fail()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 10) };
            var result = validator.Validate(new Company { Id = 1 });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_to_is_smaller_than_the_from_then_the_validator_should_throw()
        {
            MyAssert.Throws<ArgumentOutOfRangeException>(() => new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(10, 1) });
        }

        [TestMethod]
        public void When_the_validator_fails_the_error_message_should_be_set()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 10) };
            var result = validator.Validate(new Company { Id = 0 });
            result.Errors.Single().ErrorMessage.ShouldEqual("'' must be between 1 and 10 (exclusive). You entered 0.");
        }

        [TestMethod]
        public void To_and_from_properties_should_be_set()
        {
            var propertyValidator = new ExclusiveBetweenValidator(1, 10);
            propertyValidator.From.ShouldEqual(1);
            propertyValidator.To.ShouldEqual(10);
        }

        [TestMethod]
        public void When_the_value_is_between_the_range_specified_then_the_validator_should_pass_for_strings()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Name).ExclusiveBetween("aa", "zz") };
            var result = validator.Validate(new Company { Name = "bbb" });
            result.IsValid.ShouldBeTrue();
        }

        [TestMethod]
        public void When_the_value_is_smaller_than_the_range_then_the_validator_should_fail_for_strings()
        {
            var validator = new TestValidator { v => v.RuleFor(x => x.Name).ExclusiveBetween("bbb", "zz") };
            var result = validator.Validate(new Company { Name = "aaa" });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_text_is_larger_than_the_range_then_the_validator_should_fail_for_strings()
        {
            var validator = new TestValidator(v => v.RuleFor(x => x.Name).ExclusiveBetween("aaa", "bbb"));
            var result = validator.Validate(new Company { Name = "zzz" });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_value_is_exactly_the_size_of_the_upper_bound_then_the_validator_should_fail_for_strings()
        {
            var validator = new TestValidator(v => v.RuleFor(x => x.Name).ExclusiveBetween("aa", "zz"));
            var result = validator.Validate(new Company { Name = "aa" });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_value_is_exactly_the_size_of_the_lower_bound_then_the_validator_should_fail_for_strings()
        {
            var validator = new TestValidator(v => v.RuleFor(x => x.Name).ExclusiveBetween("aa", "zz"));
            var result = validator.Validate(new Company { Name = "zz" });
            result.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void When_the_to_is_smaller_than_the_from_then_the_validator_should_throw_for_strings()
        {
            MyAssert.Throws<ArgumentOutOfRangeException>(() => new ExclusiveBetweenValidator("ccc", "aaa"));
        }

        [TestMethod]
        public void When_the_validator_fails_the_error_message_should_be_set_for_strings()
        {
            var validator = new TestValidator(v => v.RuleFor(x => x.Name).ExclusiveBetween("bbb", "zzz"));
            var result = validator.Validate(new Company { Name = "aaa" });
            result.Errors.Single().ErrorMessage.ShouldEqual("'' must be between bbb and zzz (exclusive). You entered aaa.");
        }

        [TestMethod]
        public void To_and_from_properties_should_be_set_for_strings()
        {
            var validator = new ExclusiveBetweenValidator("a", "c");
            validator.From.ShouldEqual("a");
            validator.To.ShouldEqual("c");
        }

        [TestMethod]
        public void To_and_from_properties_should_be_set_for_dates()
        {
            var validator = new ExclusiveBetweenValidator(fromDate, toDate);
            validator.From.ShouldEqual(fromDate);
            validator.To.ShouldEqual(toDate);
        }

        [TestMethod]
        public void Validates_with_nullable_when_property_is_null()
        {
            var validator = new TestValidator(v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 5));
            var result = validator.Validate(new Company() {Id = 2});
            result.IsValid.ShouldBeTrue();
        }

        [TestMethod]
        public void Validates_with_nullable_when_property_not_null()
        {
            var validator = new TestValidator(v => v.RuleFor(x => x.Id).ExclusiveBetween(1, 5));
            var result = validator.Validate(new Company { Id = 10 });
            result.IsValid.ShouldBeFalse();
        }
    }
}
